package cn.virens.common.mybatis.mapper.example.mapper;

import cn.virens.common.util.core.Assert;
import cn.virens.common.util.exception.APIException;
import io.mybatis.provider.EntityColumn;
import io.mybatis.provider.EntityTable;
import io.mybatis.provider.SqlScript;
import org.apache.ibatis.builder.annotation.ProviderContext;
import org.dromara.hutool.core.io.resource.ResourceUtil;
import org.dromara.hutool.core.text.StrUtil;

import java.util.stream.Collectors;

public class ExampleProvider {
    private static final String updateFile = "META-INF/example/updateByExample.txt";
    private static final String deleteFile = "META-INF/example/deleteByExample.txt";
    private static final String selectFile = "META-INF/example/selectByExample.txt";
    private static final String countFile = "META-INF/example/countByExample.txt";

    /**
     * 根据 Example 删除
     *
     * @param providerContext 上下文
     * @return cacheKey
     */
    public static String deleteByExample(ProviderContext providerContext) throws APIException {
        return SqlScript.caching(providerContext, (e, u) -> fmt(deleteFile, e.tableName(), ""));
    }


    /**
     * 根据 Example 条件批量更新实体信息
     *
     * @param providerContext 上下文
     * @return cacheKey
     */
    public static String updateByExample(ProviderContext providerContext) throws APIException {
        return SqlScript.caching(providerContext, (e, u) -> fmt(updateFile, e.tableName(), columns1(e, u)));
    }


    /**
     * 根据 Example 条件批量更新实体不为空的字段
     *
     * @param providerContext 上下文
     * @return cacheKey
     */
    public static String updateByExampleSelective(ProviderContext providerContext) throws APIException {
        return SqlScript.caching(providerContext, (e, u) -> fmt(updateFile, e.tableName(), columns2(e, u)));
    }

    /**
     * 根据 Example 条件批量查询，根据 Example 条件查询总数，查询结果的数量由方法定义
     *
     * @param providerContext 上下文
     * @return cacheKey
     */
    public static String selectByExample(ProviderContext providerContext) throws APIException {
        return SqlScript.caching(providerContext, (e, u) -> fmt(selectFile, e.tableName(), columns0(e, u)));
    }

    /**
     * 根据 Example 条件批量查询，根据 Example 条件查询总数，查询结果的数量由方法定义
     *
     * @param providerContext 上下文
     * @return cacheKey
     */
    public static String selectCountByExample(ProviderContext providerContext) throws APIException {
        return SqlScript.caching(providerContext, (e, u) -> fmt(countFile, e.tableName(), ""));
    }

    private static String columns0(EntityTable entity, SqlScript util) throws APIException {
        return entity.columns().stream().filter(EntityColumn::selectable).map(c -> {
            if (entity.useResultMaps()) {
                return entity.tableName() + "." + c.column();
            }

            return entity.tableName() + "." + c.columnAsProperty();
        }).collect(Collectors.joining(",\r\n"));
    }

    private static String columns1(EntityTable entity, SqlScript util) throws APIException {
        return entity.columns().stream().filter(EntityColumn::updatable).map(c -> {
            return c.columnEqualsProperty("entity.");
        }).collect(Collectors.joining(",\r\n"));
    }

    private static String columns2(EntityTable entity, SqlScript util) throws APIException {
        return entity.columns().stream().filter(EntityColumn::updatable).map(c -> {
            return util.ifTest(c.notNullTest("entity."), () -> {
                return c.columnEqualsProperty("entity.") + ",";
            });
        }).collect(Collectors.joining("\r\n"));
    }

    private static String fmt(String tplPath, String t, String c) throws APIException {
        String answer = ResourceUtil.readUtf8Str(Assert.isEmpty(tplPath));

        answer = StrUtil.replace(answer, "{{TABLENAME}}", t);
        answer = StrUtil.replace(answer, "{{COLUMNS}}", c);

        return answer;
    }
}
